#include "stdafx.h"
#include "RoomTemplatesTestSuite.h"
#include "../RoomTemplates/RoomTemplates.h"
#include "../RoomTemplates/DefaultConfig.h"

using namespace CO::MyGroupNamespace::MyPackageNamespace;
using namespace CO::SpiFoundation::Configuration;
using namespace CO::SpiFoundation::Interface;

namespace CO { namespace SpiFoundation { namespace RoomFW {

RoomTemplatesTestSuite::RoomTemplatesTestSuite(void)
{
	LOG_TEST_ADD(RoomTemplatesTestSuite::main)
}

void RoomTemplatesTestSuite::setup()
{
	LoggedTestSuite::setup();
}

void RoomTemplatesTestSuite::tear_down()
{
	LoggedTestSuite::tear_down();
}

void RoomTemplatesTestSuite::main(void)
{
	try
	{
		//
		// Create and initialize container.
		//
		MyActiveInterfaceSP myAoContainer(MyActiveInterface::Create(MyActiveInterface::MY_ACTIVE_OBJECT_CONTAINER));
		TEST_ASSERT(0 != myAoContainer);
		ConfigKey config;
		config.getKey(CFG_KEY_PATH_MyConfigKey)->getValueList().push_back(ConfigValue(CFG_VAL_MyIntValue, 1L));
		TEST_ASSERT(myAoContainer->initialize(config));

		//
		// Create, initialize and wire test portal.
		//
		BindingList bindings_;
		EventPortalSP prt(new EventPortal("prt"));
		TEST_ASSERT(0 != prt);
		TEST_ASSERT(prt->initialize());
		PortalBindingSP prtB(new PortalBinding(prt, myAoContainer, MyActiveInterface::PORT_MY_PORT_1));
		TEST_ASSERT(0 != prtB);
		bindings_.push_back(prtB);
		prtB.reset();

		//
		// Get child components.
		//
		ISystemComponentSPList comps;
		comps.push_back(myAoContainer);
		myAoContainer->addChildren(comps);
		TEST_ASSERT(comps.size() > 1);

		//
		// Wire all system ports.
		//
		std::list<EventPortalSP> sm;
		BOOST_FOREACH(ISystemComponentSP comp, comps)
		{
			const PortIndex::PrimaryIndex sysPort = comp->getSystemPort();
			if (SpiFoundation::RoomFW::PortIndex::INVALID != sysPort)
			{
				EventPortalSP sys(new EventPortal("sys"));
				TEST_ASSERT(0 != sys);
				TEST_ASSERT(sys->initialize());
				sm.push_back(sys);
				bindings_.push_back(BindingSP(new PortalBinding(sys, comp, sysPort)));
			}
		}

		//
		// Start the object.
		//
		TEST_ASSERT(myAoContainer->start(wait_));

		//
		// Test system port response.
		//
		BOOST_FOREACH(EventPortalSP sys, sm)
		{
			sys->sendMessage(MyProtocol::I_AM_READY);
			TEST_ASSERT(sys->wait(wait_));
			RoomMessageSP message = sys->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::I_AM_READY_ACK == message->messageID());
		}

		//
		// Test message 1 response.
		//
		IPayloadSP sndData(new MyPayload(42.42));
		TEST_ASSERT(0 != sndData);
		prt->sendMessage(MyProtocol::IN_MESSAGE_1, IPayload::ReleaseOwnership(sndData));
		TEST_ASSERT(prt->wait(wait_));
		RoomMessageSP message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_1 == message->messageID());
		MyPayloadSP rcvData = ::boost::static_pointer_cast<MyPayload, IPayload>(message->payload());
		TEST_ASSERT(42.42 == rcvData->value());
		TEST_ASSERT(prt->wait(wait_));
		message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_1 == message->messageID());
		rcvData = ::boost::static_pointer_cast<MyPayload, IPayload>(message->payload());
		TEST_ASSERT(42.42 == rcvData->value());

		//
		// Test message 2 response.
		//
		prt->sendMessage(MyProtocol::IN_MESSAGE_2);
		TEST_ASSERT(prt->wait(wait_));
		message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_2 == message->messageID());
		TEST_ASSERT(prt->wait(wait_));
		message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_2 == message->messageID());

		//
		// Test message 3 response.
		//
		prt->sendMessage(MyProtocol::IN_MESSAGE_3, IPayload::ReleaseOwnership(sndData));
		TEST_ASSERT(prt->wait(wait_));
		message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_3 == message->messageID());
		TEST_ASSERT(prt->wait(wait_));
		message = prt->getMessage();
		TEST_ASSERT(0 != message);
		TEST_ASSERT(MyProtocol::OUT_MESSAGE_3 == message->messageID());

		//
		// Test error response
		//
		prt->sendMessage(MyProtocol::IN_ERROR_1);
		for (int i = 0; i < 2; ++i) // should get 2 responses.
		{
			TEST_ASSERT(prt->wait(wait_));
			message = prt->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::OUT_ERROR == message->messageID());
			SpiControl::Protocol::ErrorPayloadSP errorPayload = ::boost::static_pointer_cast<SpiControl::Protocol::ErrorPayload>(message->payload());
			TEST_ASSERT(0 != errorPayload);
			TEST_ASSERT(0 != errorPayload->value());
			TEST_ASSERT(strstr(errorPayload->value()->what(), "Fatal Error"));
			G_LOG_1_ERROR("Test Suite: %s", errorPayload->value()->what());
		}
		prt->sendMessage(MyProtocol::IN_ERROR_2);
		for (int i = 0; i < 2; ++i) // should get 2 responses.
		{
			TEST_ASSERT(prt->wait(wait_));
			message = prt->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::OUT_ERROR == message->messageID());
			SpiControl::Protocol::ErrorPayloadSP errorPayload = ::boost::static_pointer_cast<SpiControl::Protocol::ErrorPayload>(message->payload());
			TEST_ASSERT(0 != errorPayload);
			TEST_ASSERT(0 != errorPayload->value());
			TEST_ASSERT(strstr(errorPayload->value()->what(), "Fatal Exception"));
			G_LOG_1_ERROR("Test Suite: %s", errorPayload->value()->what());
		}
		prt->sendMessage(MyProtocol::IN_ERROR_3);
		for (int i = 0; i < 2; ++i) // should get 2 responses.
		{
			TEST_ASSERT(prt->wait(wait_));
			message = prt->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::OUT_ERROR == message->messageID());
			SpiControl::Protocol::ErrorPayloadSP errorPayload = ::boost::static_pointer_cast<SpiControl::Protocol::ErrorPayload>(message->payload());
			TEST_ASSERT(0 != errorPayload);
			TEST_ASSERT(0 != errorPayload->value());
			TEST_ASSERT(strstr(errorPayload->value()->what(), "Catch-all Exception"));
			G_LOG_1_ERROR("Test Suite: %s", errorPayload->value()->what());
		}
		prt->sendMessage(MyProtocol::IN_ERROR_4);
		for (int i = 0; i < 2; ++i) // should get 2 responses.
		{
			TEST_ASSERT(prt->wait(wait_));
			message = prt->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::OUT_ERROR == message->messageID());
			SpiControl::Protocol::ErrorPayloadSP errorPayload = ::boost::static_pointer_cast<SpiControl::Protocol::ErrorPayload>(message->payload());
			TEST_ASSERT(0 != errorPayload);
			TEST_ASSERT(0 != errorPayload->value());
			TEST_ASSERT(strstr(errorPayload->value()->what(), "PORT_TIMER:TIMER_MESSAGE"));
			G_LOG_1_ERROR("Test Suite: %s", errorPayload->value()->what());
		}

		//
		prt->sendMessage(MyProtocol::IN_ERROR_5);
		for (int i = 0; i < 2; ++i) // should get 2 responses.
		{
			TEST_ASSERT(prt->wait(wait_));
			message = prt->getMessage();
			TEST_ASSERT(0 != message);
			TEST_ASSERT(MyProtocol::OUT_ERROR == message->messageID());
			SpiControl::Protocol::ErrorPayloadSP errorPayload = ::boost::static_pointer_cast<SpiControl::Protocol::ErrorPayload>(message->payload());
			TEST_ASSERT(0 != errorPayload);
			TEST_ASSERT(0 != errorPayload->value());
			TEST_ASSERT(strstr(errorPayload->value()->what(), "UNKNOWN_PORT:UNKNOWN_MESSAGE"));
			G_LOG_1_ERROR("Test Suite: %s", errorPayload->value()->what());
		}
		// Stop object and cleanup.
		//
		TEST_ASSERT(myAoContainer->stop(wait_));
		bindings_.clear();
		sm.clear();
		prt.reset();
		myAoContainer.reset();
	}
	catch (SpiFoundation::RoomFW::SendMessageError& e)
	{
		G_LOG_0(SpiFoundation::RoomFW::LV_ERROR, e.what());
		TEST_ASSERT_MSG(false, e.what());
	}
	catch (SpiFoundation::ErrorHandling::IError& e)
	{
		G_LOG_0(SpiFoundation::RoomFW::LV_ERROR, e.what());
		TEST_ASSERT_MSG(false, e.what());
	}
	catch (std::runtime_error& e)
	{
		G_LOG_0(SpiFoundation::RoomFW::LV_ERROR, e.what());
		TEST_ASSERT_MSG(false, e.what());
	}
	catch (std::exception& e)
	{
		G_LOG_0(SpiFoundation::RoomFW::LV_ERROR, e.what());
		TEST_ASSERT_MSG(false, e.what());
	}
	catch (...) // You must enable SEH exceptions to catch hardware (e.g. memory access) errors.
	{
		G_LOG_0(SpiFoundation::RoomFW::LV_ERROR, "Unhandled Exception");
		TEST_ASSERT_MSG(false, "Unhandled Exception");
	}
}

}}}
